/**
 * 
 */
package com.maohi.software.arii.modules;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.maohi.software.arii.jaxb2.Plugin;
import com.maohi.software.arii.jaxb2.Plugin.ExtensionPoints.ExtensionPoint;
import com.maohi.software.arii.jaxb2.Plugin.Extensions.Extension;
import com.maohi.software.arii.utils.TypeLiterals;

/**
 * @author heifara
 * 
 */
public class ExtensionPointModule extends AbstractModule {

	private static class MapExtensionPointListExtension implements Provider<Map<ExtensionPoint, List<Extension>>> {
		private static Logger logger = Logger.getLogger(ExtensionPointModule.MapExtensionPointListExtension.class.getName());

		private Map<String, List<Extension>> extensions;
		private Map<String, List<ExtensionPoint>> extensionPoints;

		@Override
		public Map<ExtensionPoint, List<Extension>> get() {
			try {
				Map<ExtensionPoint, List<Extension>> iResults = new LinkedHashMap<Plugin.ExtensionPoints.ExtensionPoint, List<Extension>>();
				for (List<ExtensionPoint> iExtensionPoints : this.extensionPoints.values()) {
					for (ExtensionPoint iExtensionPoint : iExtensionPoints) {
						List<Extension> iExtensions = iResults.get(iExtensionPoint);
						if (iExtensions == null) {
							iExtensions = new ArrayList<Extension>();
							iResults.put(iExtensionPoint, iExtensions);
						}

						if (this.extensions.get(iExtensionPoint.getId()) != null) {
							iExtensions.addAll(this.extensions.get(iExtensionPoint.getId()));
						}
					}
				}
				return iResults;
			} catch (Exception aException) {
				logger.error(aException.getMessage(), aException);
				return null;
			}
		}

		@Inject
		public void init(Map<String, List<ExtensionPoint>> aExtensionPoints, Map<String, List<Extension>> aExtensions) {
			this.extensionPoints = aExtensionPoints;
			this.extensions = aExtensions;
		}
	}

	private static class MapStringListExtension implements Provider<Map<String, List<Extension>>> {
		private static Logger logger = Logger.getLogger(ExtensionPointModule.MapStringListExtension.class.getName());

		private Map<String, Plugin> plugins;

		public MapStringListExtension(Map<String, Plugin> aPlugins) {
			this.plugins = aPlugins;
		}

		@Override
		public Map<String, List<Extension>> get() {
			try {
				Map<String, List<Extension>> iResults = new LinkedHashMap<String, List<Extension>>();
				Iterator<Plugin> iIterator = this.plugins.values().iterator();
				while (iIterator.hasNext()) {
					Plugin iPlugin = iIterator.next();
					for (Extension iExtension : iPlugin.getExtensions().getExtension()) {
						List<Extension> iExtensions = iResults.get(iExtension.getId());
						if (iExtensions == null) {
							iExtensions = new ArrayList<Plugin.Extensions.Extension>();
							iResults.put(iExtension.getId(), iExtensions);
						}
						iExtensions.add(iExtension);
					}
				}
				return iResults;
			} catch (Exception aException) {
				logger.error(aException.getMessage(), aException);
				return null;
			}
		}
	}

	private static class MapStringListExtensionPoint implements Provider<Map<String, List<ExtensionPoint>>> {
		private static Logger logger = Logger.getLogger(MapStringListExtensionPoint.class.getName());

		private Map<String, Plugin> plugins;

		public MapStringListExtensionPoint(Map<String, Plugin> aPlugins) {
			this.plugins = aPlugins;
		}

		@Override
		public Map<String, List<ExtensionPoint>> get() {
			try {
				Map<String, List<ExtensionPoint>> iResults = new LinkedHashMap<String, List<ExtensionPoint>>();
				Iterator<Plugin> iIterator = this.plugins.values().iterator();
				while (iIterator.hasNext()) {
					Plugin iPlugin = iIterator.next();
					for (ExtensionPoint iExtensionPoint : iPlugin.getExtensionPoints().getExtensionPoint()) {
						List<ExtensionPoint> iExtensionPoints = iResults.get(iExtensionPoint.getId());
						if (iExtensionPoints == null) {
							iExtensionPoints = new ArrayList<Plugin.ExtensionPoints.ExtensionPoint>();
							iResults.put(iExtensionPoint.getId(), iExtensionPoints);
						}
						iExtensionPoints.add(iExtensionPoint);
					}
				}
				return iResults;
			} catch (Exception aException) {
				logger.error(aException.getMessage(), aException);
				return null;
			}
		}

	}

	private static Logger logger = Logger.getLogger(ExtensionPointModule.class.getName());
	private Map<String, Plugin> plugins;

	@Override
	protected void configure() {
		try {
			this.bind(TypeLiterals.getMapStringListExtension()).toProvider(new MapStringListExtension(this.plugins));
			this.bind(TypeLiterals.getMapStringListExtensionPoint()).toProvider(new MapStringListExtensionPoint(this.plugins));
			this.bind(TypeLiterals.getMapExtensionPointListExtension()).toProvider(new MapExtensionPointListExtension());
		} catch (Exception aException) {
			logger.error(aException.getMessage(), aException);
		}

	}

	@Inject
	private void init(Map<String, Plugin> aPlugins) {
		this.plugins = aPlugins;
	}

}
